<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>src/class.scenegraph.js - sceneGraph.js</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/3.9.1/build/cssgrids/cssgrids-min.css">
    <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
    <link rel="stylesheet" href="../assets/css/main.css" id="site_styles">
    <link rel="shortcut icon" type="image/png" href="../assets/favicon.png">
    <script src="http://yui.yahooapis.com/combo?3.9.1/build/yui/yui-min.js"></script>
</head>
<body class="yui3-skin-sam">

<div id="doc">
    <div id="hd" class="yui3-g header">
        <div class="yui3-u-3-4">
            
                <h1><img src="../../logo/logoCGSG_256x57.png" title="sceneGraph.js"></h1>
            
        </div>
        <div class="yui3-u-1-4 version">
            <em>API Docs for: v2.1.0</em>
        </div>
    </div>
    <div id="bd" class="yui3-g">

        <div class="yui3-u-1-4">
            <div id="docs-sidebar" class="sidebar apidocs">
                <div id="api-list">
    <h2 class="off-left">APIs</h2>
    <div id="api-tabview" class="tabview">
        <ul class="tabs">
            <li><a href="#api-classes">Classes</a></li>
            <li><a href="#api-modules">Modules</a></li>
        </ul>

        <div id="api-tabview-filter">
            <input type="search" id="api-filter" placeholder="Type to filter APIs">
        </div>

        <div id="api-tabview-panel">
            <ul id="api-classes" class="apis classes">
            
                <li><a href="../classes/CGSG.html">CGSG</a></li>
            
                <li><a href="../classes/CGSGAccordion.html">CGSGAccordion</a></li>
            
                <li><a href="../classes/CGSGAnimationManager.html">CGSGAnimationManager</a></li>
            
                <li><a href="../classes/CGSGAnimationMethod.html">CGSGAnimationMethod</a></li>
            
                <li><a href="../classes/CGSGBindEntry.html">CGSGBindEntry</a></li>
            
                <li><a href="../classes/CGSGButtonMode.html">CGSGButtonMode</a></li>
            
                <li><a href="../classes/CGSGCollisionGhostOnDemandTester.html">CGSGCollisionGhostOnDemandTester</a></li>
            
                <li><a href="../classes/CGSGCollisionManager.html">CGSGCollisionManager</a></li>
            
                <li><a href="../classes/CGSGCollisionMethod.html">CGSGCollisionMethod</a></li>
            
                <li><a href="../classes/CGSGCollisionRegionTester.html">CGSGCollisionRegionTester</a></li>
            
                <li><a href="../classes/CGSGCollisionTesterFactory.html">CGSGCollisionTesterFactory</a></li>
            
                <li><a href="../classes/CGSGColor.html">CGSGColor</a></li>
            
                <li><a href="../classes/CGSGCSSManager.html">CGSGCSSManager</a></li>
            
                <li><a href="../classes/CGSGDimension.html">CGSGDimension</a></li>
            
                <li><a href="../classes/CGSGEvent.html">CGSGEvent</a></li>
            
                <li><a href="../classes/CGSGEventManager.html">CGSGEventManager</a></li>
            
                <li><a href="../classes/CGSGHandleBox.html">CGSGHandleBox</a></li>
            
                <li><a href="../classes/CGSGImgManager.html">CGSGImgManager</a></li>
            
                <li><a href="../classes/CGSGInterpolator.html">CGSGInterpolator</a></li>
            
                <li><a href="../classes/CGSGInterpolatorLinear.html">CGSGInterpolatorLinear</a></li>
            
                <li><a href="../classes/CGSGInterpolatorTCB.html">CGSGInterpolatorTCB</a></li>
            
                <li><a href="../classes/CGSGKeyFrame.html">CGSGKeyFrame</a></li>
            
                <li><a href="../classes/CGSGMap.html">CGSGMap</a></li>
            
                <li><a href="../classes/CGSGMask.html">CGSGMask</a></li>
            
                <li><a href="../classes/CGSGMaskCache.html">CGSGMaskCache</a></li>
            
                <li><a href="../classes/CGSGMaskClip.html">CGSGMaskClip</a></li>
            
                <li><a href="../classes/CGSGMath.html">CGSGMath</a></li>
            
                <li><a href="../classes/CGSGNode.html">CGSGNode</a></li>
            
                <li><a href="../classes/CGSGNodeButton.html">CGSGNodeButton</a></li>
            
                <li><a href="../classes/CGSGNodeCircle.html">CGSGNodeCircle</a></li>
            
                <li><a href="../classes/CGSGNodeColorPicker.html">CGSGNodeColorPicker</a></li>
            
                <li><a href="../classes/CGSGNodeCurveTCB.html">CGSGNodeCurveTCB</a></li>
            
                <li><a href="../classes/CGSGNodeDomElement.html">CGSGNodeDomElement</a></li>
            
                <li><a href="../classes/CGSGNodeEllipse.html">CGSGNodeEllipse</a></li>
            
                <li><a href="../classes/CGSGNodeImage.html">CGSGNodeImage</a></li>
            
                <li><a href="../classes/CGSGNodeLine.html">CGSGNodeLine</a></li>
            
                <li><a href="../classes/CGSGNodeSlider.html">CGSGNodeSlider</a></li>
            
                <li><a href="../classes/CGSGNodeSliderHandle.html">CGSGNodeSliderHandle</a></li>
            
                <li><a href="../classes/CGSGNodeSprite.html">CGSGNodeSprite</a></li>
            
                <li><a href="../classes/CGSGNodeSquare.html">CGSGNodeSquare</a></li>
            
                <li><a href="../classes/CGSGNodeTabMenu.html">CGSGNodeTabMenu</a></li>
            
                <li><a href="../classes/CGSGNodeText.html">CGSGNodeText</a></li>
            
                <li><a href="../classes/CGSGNodeWebview.html">CGSGNodeWebview</a></li>
            
                <li><a href="../classes/CGSGParticle.html">CGSGParticle</a></li>
            
                <li><a href="../classes/CGSGParticleEmitter.html">CGSGParticleEmitter</a></li>
            
                <li><a href="../classes/CGSGParticleSystem.html">CGSGParticleSystem</a></li>
            
                <li><a href="../classes/CGSGPickNodeMethod.html">CGSGPickNodeMethod</a></li>
            
                <li><a href="../classes/CGSGPosition.html">CGSGPosition</a></li>
            
                <li><a href="../classes/CGSGRegion.html">CGSGRegion</a></li>
            
                <li><a href="../classes/CGSGRotation.html">CGSGRotation</a></li>
            
                <li><a href="../classes/CGSGScale.html">CGSGScale</a></li>
            
                <li><a href="../classes/CGSGSceneGraph.html">CGSGSceneGraph</a></li>
            
                <li><a href="../classes/CGSGSection.html">CGSGSection</a></li>
            
                <li><a href="../classes/CGSGTimeline.html">CGSGTimeline</a></li>
            
                <li><a href="../classes/CGSGTraverser.html">CGSGTraverser</a></li>
            
                <li><a href="../classes/CGSGVector2D.html">CGSGVector2D</a></li>
            
                <li><a href="../classes/CGSGView.html">CGSGView</a></li>
            
                <li><a href="../classes/CGSGWEBVIEWMODE.html">CGSGWEBVIEWMODE</a></li>
            
                <li><a href="../classes/CGSGWrapMode.html">CGSGWrapMode</a></li>
            
                <li><a href="../classes/GLOBAL_CONSTANTS.html">GLOBAL_CONSTANTS</a></li>
            
                <li><a href="../classes/GLOBAL_METHODS.html">GLOBAL_METHODS</a></li>
            
                <li><a href="../classes/GLOBAL_PROPERTIES.html">GLOBAL_PROPERTIES</a></li>
            
                <li><a href="../classes/UTIL_ARRAY.html">UTIL_ARRAY</a></li>
            
                <li><a href="../classes/WUICCGSGNodeImageFactory.html">WUICCGSGNodeImageFactory</a></li>
            
            </ul>

            <ul id="api-modules" class="apis modules">
            
                <li><a href="../modules/Animation.html">Animation</a></li>
            
                <li><a href="../modules/Collision.html">Collision</a></li>
            
                <li><a href="../modules/Math.html">Math</a></li>
            
                <li><a href="../modules/Node.html">Node</a></li>
            
                <li><a href="../modules/ParticleSystem.html">ParticleSystem</a></li>
            
                <li><a href="../modules/Scene.html">Scene</a></li>
            
                <li><a href="../modules/Util.html">Util</a></li>
            
            </ul>
        </div>
    </div>
</div>

            </div>
        </div>
        <div class="yui3-u-3-4">
                <div id="api-options">
        Show:
        <label for="api-show-inherited">
            <input type="checkbox" id="api-show-inherited" checked>
            Inherited
        </label>

        <label for="api-show-protected">
            <input type="checkbox" id="api-show-protected">
            Protected
        </label>

        <label for="api-show-private">
            <input type="checkbox" id="api-show-private">
            Private
        </label>
        <label for="api-show-deprecated">
            <input type="checkbox" id="api-show-deprecated">
            Deprecated
        </label>

    </div>


            <div class="apidocs">
                <div id="docs-main">
                    <div class="content">
                        <h1 class="file-heading">File: src/class.scenegraph.js</h1>

<div class="file">
    <pre class="code prettyprint linenums">
/*
 * Copyright (c) 2014 Gwennael Buchet
 *
 * License/Terms of Use
 *
 * Permission is hereby granted, free of charge and for the term of intellectual property rights on the Software, to any
 * person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to use, copy, modify
 * and propagate free of charge, anywhere in the world, all or part of the Software subject to the following mandatory conditions:
 *
 *   •    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 *  Any failure to comply with the above shall automatically terminate the license and be construed as a breach of these
 *  Terms of Use causing significant harm to Gwennael Buchet.
 *
 *  THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 *  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
 *  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 *  Except as contained in this notice, the name of Gwennael Buchet shall not be used in advertising or otherwise to promote
 *  the use or other dealings in this Software without prior written authorization from Gwennael Buchet.
 *
 *  These Terms of Use are subject to French law.
 */

/**
 * Represent the scene graph it self.
 *
 * @class CGSGSceneGraph
 * @module Scene
 * @constructor
 * @extends {Object}
 * @param {HTMLElement} canvas a handler to the canvas HTML element
 * @param {CanvasRenderingContext2D} context context to render on
 * @type {CGSGSceneGraph}
 * @author Gwennael Buchet (gwennael.buchet@gmail.com)
 */
var CGSGSceneGraph = CGSGObject.extend(
    {
        initialize: function (canvas, context) {

            /**
             * Root node of the graph
             * @property root
             * @type {CGSGNode}
             */
            this.root = null;

            /**
             * @property context
             * @type {CanvasRenderingContext2D}
             */
            this.context = context;

            /**
             *
             * @property _nextNodeID
             * @type {Number}
             * @private
             */
            this._nextNodeID = 1;

            ///// INITIALIZATION //////

            /**
             * Initialize a ghost canvas used to determine which nodes are selected by the user
             * @property ghostCanvas
             * @type {HTMLElement}
             */
            this.ghostCanvas = document.createElement(&#x27;canvas&#x27;);
            this.initializeGhost(canvas.width, canvas.height);

            //fixes a problem where double clicking causes text to get selected on the canvas
            CGSG.canvas.onselectstart = function () {
                return false;
            };
        },

        /**
         * Initialize the ghost rendering, used by the PickNode function
         * @private
         * @method initializeGhost
         * @param w {Number} width The width for the canvas. Must be the same as the rendering canvas
         * @param h {Number} height The height for the canvas. Must be the same as the rendering canvas
         * */
        initializeGhost: function (w, h) {
            this.ghostCanvas.height = h;
            this.ghostCanvas.width = w;
            //noinspection JSUndeclaredVariable
            CGSG.ghostContext = this.ghostCanvas.getContext(&#x27;2d&#x27;);
        },

        /**
         * Used to enforce theme invalidation for each node during next rendering loop
         * @method invalidateTheme
         */
        invalidateTheme: function () {
            this._invalidateThemeRecursive(this.root);
        },

        /**
         * @method _invalidateThemeRecursive
         * @param n
         * @private
         */
        _invalidateThemeRecursive: function (n) {
            if (cgsgExist(n)) {
                n.invalidateTheme();

                for (var i = 0, len = n.children.length; i &lt; len; ++i) {
                    this._invalidateThemeRecursive(n.children[i]);
                }
            }
        },

        /**
         * Render the SceneGraph
         * @public
         * @method render
         * */
        render: function () {
            //erase previous rendering
            cgsgClearContext(this.context);
            var i, node;

            if (cgsgExist(this.root)) {
                var evt, key = null;
                //set the new values for all the animated nodes
                if (CGSG.animationManager.listTimelines.length &gt; 0) {
                    node = null;
                    var value, tl; //tl = timeline
                    for (i = CGSG.animationManager.listTimelines.length - 1; i &gt;= 0; --i) {
                        tl = CGSG.animationManager.listTimelines[i];
                        node = tl.parentNode;

                        if (node.isVisible) {
                            value = tl.getValue(CGSG.currentFrame);
                            if (value !== undefined) {
                                node.evalSet(tl.attribute, value);
                                if (tl.onAnimate !== null) {
                                    CGSG.eventManager.dispatch(tl, cgsgEventTypes.ON_ANIMATE,
                                                               new CGSGEvent(this,
                                                                             {node: node, attribute: tl.attribute, value: value}));
                                }
                            }

                            //fire event if this is the first animation key for this tl
                            key = tl.getFirstKey();
                            if (key !== null &amp;&amp; key.frame === CGSG.currentFrame &amp;&amp;
                                tl.onAnimationStart !== null) {
                                evt = new CGSGEvent(this, {node: node});
                                evt.node = node;
                                CGSG.eventManager.dispatch(tl, cgsgEventTypes.ON_ANIMATION_START, evt);
                            }

                            //fire event if this is the last animation key for this tl
                            key = tl.getLastKey();
                            if (key !== null &amp;&amp; key.frame == CGSG.currentFrame) {
                                tl.removeAll();
                                if (tl.onAnimationEnd !== null) {
                                    evt = new CGSGEvent(this, {node: node});
                                    evt.node = node;
                                    evt.attribute = tl.attribute;
                                    CGSG.eventManager.dispatch(tl, cgsgEventTypes.ON_ANIMATION_END, evt);
                                }
                            }
                        }
                    }
                }

                //run the rendering traverser
                this.context.save();
                this.context.scale(CGSG.displayRatio.x, CGSG.displayRatio.y);
                if (this.root.isVisible) {
                    this.root.doRender(this.context);
                }
                this.context.restore();
            }

            //draw the selection markers around the selected nodes
            if (CGSG.isBoundingBoxOnTop &amp;&amp; CGSG.selectedNodes.length &gt; 0) {
                for (i = CGSG.selectedNodes.length - 1; i &gt;= 0; i--) {
                    node = CGSG.selectedNodes[i];
                    if (node.isVisible) {
                        //todo valider l&#x27;interet de calculer la matrice absolue
                        node.computeAbsoluteMatrix(true);

                        this.context.save();
                        this.context.scale(CGSG.displayRatio.x, CGSG.displayRatio.y);

                        var t = node.getAbsPosition();

                        this.context.translate(t.x, t.y);

                        if (cgsgExist(node.rotationCenter)) {

                            this.context.translate(node.dimension.width * node.rotationCenter.x,
                                                   node.dimension.height * node.rotationCenter.y);
                            this.context.rotate(node.rotation.angle);
                            this.context.translate(-node.dimension.width * node.rotationCenter.x,
                                                   -node.dimension.height * node.rotationCenter.y);
                        }
                        else {
                            this.context.rotate(node.rotation.angle);
                        }
                        this.context.scale(node._absSca.x, node._absSca.y);

                        node.renderBoundingBox(this.context);
                        this.context.restore();
                    }
                }
            }

            CGSG.currentFrame++;
        },

        /**
         * Change the dimension of the canvas.
         * Does not really change the dimension of the rendering canvas container,
         *  but is used for different computations
         * @method setCanvasDimension
         * @param {CGSGDimension} newDimension
         * */
        setCanvasDimension: function (newDimension) {
            this.initializeGhost(newDimension.width, newDimension.height);
        },

        /**
         * Mark the nodes as selected so the select marker (also called selectedHandlers)
         *  will be shown and the SceneGraph will manage the moving and resizing of the selected objects.
         * @method selectNode
         * @param nodeToSelect The CGSGNode to be selected
         * */
        selectNode: function (nodeToSelect) {
            if (!nodeToSelect.isSelected) {
                nodeToSelect.setSelected(true);
                nodeToSelect.computeAbsoluteMatrix(false);
                CGSG.selectedNodes[CGSG.selectedNodes.length] = nodeToSelect;
            }
        },

        /**
         * Mark the nodes as not selected
         * @method deselectNode
         * @param {CGSGNode} nodeToDeselect
         * */
        deselectNode: function (nodeToDeselect) {
            nodeToDeselect.setSelected(false);
            /*CGSG.selectedNodes = */
            CGSG.selectedNodes.without(nodeToDeselect);
        },

        /**
         * Mark all nodes as not selected
         * @method deselectAll
         * @param {Array} excludedArray CGSGNodes to not deselect
         * */
        deselectAll: function (excludedArray) {
            var node = null;
            for (var i = CGSG.selectedNodes.length - 1; i &gt;= 0; i--) {
                node = CGSG.selectedNodes[i];
                if (!cgsgExist(excludedArray) || !excludedArray.contains(node)) {
                    this.deselectNode(node);
                }
            }

            //just to be sure
            CGSG.selectedNodes.clear();
        },

        /**
         * Recursively traverse the nodes and return the one who is under the mouse coordinates
         * @method pickNode
         * @param {CGSGPosition} mousePosition
         * @param {String} condition
         * @return {CGSGNode}
         * @example
         *  this.scenegraph.picknode(mousePosition, &#x27;position.x &gt; 100&#x27;); &lt;br/&gt;
         *  this.scenegraph.picknode(mousePosition, &#x27;position.x &gt; 100 &amp;&amp; this.position.y &gt; 100&#x27;);
         */
        pickNode: function (mousePosition, condition) {
            //empty the current selection first
            //CGSG.selectedNodes = new Array();
            cgsgClearContext(CGSG.ghostContext);
            //recursively traverse the nodes to get the selected nodes
            if (!cgsgExist(this.root)) {
                return null;
            }
            else {
                return this.root.pickNode(
                    mousePosition.copy(), //position of the cursor on the viewport
                    new CGSGScale(1, 1), //absolute scale for the nodes
                    CGSG.ghostContext, //context for the ghost rendering
                    true, //recursively ?
                    //CGSG.canvas.width / CGSG.displayRatio.x, CGSG.canvas.height / CGSG.displayRatio.y,
                    //dimension of the canvas container
                    condition);  // condition to the picknode be executed
            }
        },

        /**
         * Recursively traverse the nodes and return the ones who are under the mouse coordinates
         * @method pickNodes
         * @param {CGSGRegion} region
         * @param {String} condition
         * @return {Array}
         * @example
         *  this.scenegraph.picknodes(region, &#x27;position.x &gt; 100&#x27;); &lt;br/&gt;
         *  this.scenegraph.picknodes(region, &#x27;position.x &gt; 100 &amp;&amp; this.position.y &gt; 100&#x27;);
         */
        pickNodes: function (region, condition) {
            //empty the current selection first
            //CGSG.selectedNodes = new Array();
            cgsgClearContext(CGSG.ghostContext);
            //recursively traverse the nodes to get the selected nodes
            if (!cgsgExist(this.root)) {
                return null;
            }
            else {
                return this.root.pickNodes(
                    region.copy(), //position of the cursor on the viewport
                    new CGSGScale(1, 1), //absolute scale for the nodes
                    CGSG.ghostContext, //context for the ghost rendering
                    true, //recursively ?
                    //CGSG.canvas.width / CGSG.displayRatio.x, CGSG.canvas.height / CGSG.displayRatio.y,
                    //dimension of the canvas container
                    condition);  // condition to the picknode be executed
            }
        },

        /**
         * Remove the child nodes passed in parameter, from the root nodes
         * @method removeNode
         * @param {CGSGNode} node the nodes to remove
         * @return {Boolean} true if the nodes was found and removed
         * */
        removeNode: function (node) {
            if (cgsgExist(node)) {
                this.deselectNode(node);
                if (this.root !== null) {
                    return this.root.removeChild(node, true);
                }
            }
            return false;
        },

        /**
         * Add a node on the scene.
         * If the root does not already exist, this node will be used as root
         * @method addNode
         * @param {CGSGNode} node the node to add
         * @param {CGSGNode} parent the parent node of the new one. If it&#x27;s null, the node will be the root.
         * */
        addNode: function (node, parent) {
            node._id = this._nextNodeID++;
            if (this.root === null) {
                this.root = node;
            }
            else {
                if (parent === null) {
                    parent = this.root;
                }
                parent.addChild(node);
            }
        }
    }
);

    </pre>
</div>

                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="../assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src="../assets/js/yui-prettify.js"></script>
<script src="../assets/../api.js"></script>
<script src="../assets/js/api-filter.js"></script>
<script src="../assets/js/api-list.js"></script>
<script src="../assets/js/api-search.js"></script>
<script src="../assets/js/apidocs.js"></script>
</body>
</html>
